home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
SMALLTAL
/
FRACTALW
/
FRACTAL_.WOR
next >
Wrap
Text File
|
1990-10-27
|
8KB
|
301 lines
"
FractalWorkspace class
I developed this class to learn about Digitalk Smalltalk/V
and to implement Clifford A. Pickover's cyclic system as
described in Computers & Graphics, vol. 11, #2, pgs 217-226.
This file is in Digitalk's fileOut format and can therefore
be filed in directly. To run the graphics execute the following:
FractalWorkspace new open.
Choose restart in the Fractals menu.
The supplied settings do not produce very striking pictures; they
correspond to fig. 1a in the above paper. To get more detail, the
sampling rectangle can be made smaller. Many other parameters can
be varied. The menu item 'fillin' will start an iteration sequence
from the location of a mouseclick.
The key methods for controlling the graphics are:
1) iterTimes:at: -- the controlling equation
2) reframe: -- the initial parameter settings
3) open -- window size, etc.
This was developed on my Mac Plus at home and runs fine on it.
I've occasionally run it on a Mac IIx and have had no problems
there either. No surprises are expected since Digitalk Smalltalk
takes care of porting the application. The extra computing power
of the IIx is almost necessary.
There are all sorts of extensions I'd like to implement, 'actual'
fractals, refinements of the iteration methods, ... I usually
don't have the time to do much work on this. I would welcome any
suggestions and/or contributions to the methods and classes.
Jeff Green
CIS:71170,726
"
Object subclass: #FractalWorkspace
instanceVariableNames:
'rectangle pen center scaleFactor plotRect resolution iterationTimes magnification menu menuItem '
classVariableNames: ''
poolDictionaries:
'FunctionKeys ' !
!FractalWorkspace class methods ! !
!FractalWorkspace methods !
click: aPoint
"If fillin, start an iteration from click point."
| point scale orig pointGlobal |
(menuItem = 'fillin') & EventRecord mouseDown ifTrue: [
EventRecord waitForMouseUp.
pointGlobal := EventRecord mousePointGlobal.
point := EventRecord mousePoint.
EventRecord getNextEvent.
(Scheduler activeWindow screenRect containsPoint: pointGlobal) ifFalse:
[^ self ].
scale := magnification * scaleFactor.
orig := center - (plotRect origin + (plotRect extent / 2) * scale).
point := (point - orig)/scale.
CursorManager normal.
menu enable: #stop.
self iterTimes:iterationTimes at: point.
].!
cyclicSys
"Generate plots which iterate based on the
╞x = -h*f(y), ╞y = h*f(x) system of equations.
"
| label |
label := 'from: ',
plotRect origin printString,
', to: ',
plotRect corner printString,
', iters=',
iterationTimes printString,
', res.=',
resolution printString,
', mag.=',
self magnification printString.
Scheduler topDispatcher pane
label: label;
displayLabel.
Display white: rectangle.
menu disable: #restart.
menu disable: #fillin.
menu enable: #stop.
plotRect left to: plotRect right
by: (plotRect right - plotRect left)/resolution
do: [ :x |
plotRect bottom to: plotRect top
by: (plotRect top - plotRect bottom)/resolution
do: [ :y |
self iterTimes: iterationTimes at: x@y.
menuItem = 'stop'
ifTrue: [
^self
].
]
].
menu enable: #restart.
menu enable: #fillin.
menu disable: #stop.!
fillin
"select start points"
menu disable: #fillin.
CursorManager hair.
menuItem := 'fillin'.!
stop
"stop drawing"
menu enable: #restart.
menu enable: #fillin.
menu disable: #stop.
menuItem := 'stop'.!
form: aRectangle
"Make a form for the demo window and return it."
^ Form new
width: aRectangle width height: aRectangle height!
from: oPoint to: cPoint
"sets phase space boundaries."
plotRect isNil
ifTrue: [ plotRect := Rectangle new ].
plotRect origin: oPoint corner: cPoint.
scaleFactor := (rectangle width)/(plotRect right - plotRect left) min:
((rectangle height)/(plotRect top - plotRect bottom)).!
iterations: aNum
"Sets iterationTimes to aNum."
iterationTimes := aNum.!
iterTimes: aNum at: aPoint
"Iterate aNum times starting at aPoint."
| x y x0 y0 orig scale myMenuBarRect |
scale := magnification * scaleFactor.
orig := center - (plotRect origin + (plotRect extent / 2) * scale).
x0 := aPoint x.
y0 := aPoint y.
pen up;
goto: (orig + (x0@y0*scale)) truncated;
down.
myMenuBarRect := Scheduler menuBar menuBarRectangle.
aNum timesRepeat: [
x := x0 - (0.1*((((3*y0) sin) + y0) sin)).
y := y0 + (0.1*((((3*x0) sin) + x0) sin)).
pen
goto: (orig + (x@y*scale)) truncated.
x0 := x.
y0 := y.
EventRecord mouseDown ifTrue: [
(myMenuBarRect containsPoint:
(EventRecord mousePointGlobal )) ifTrue: [
Scheduler inMenuBar.
menuItem = 'stop' ifTrue: [ ^self].
].
EventRecord getNextEvent.
].
].!
magnification
"Returns magnification."
^magnification / 0.5.!
magnification: aNum
"Sets magnification to aNum."
magnification := aNum * 0.5.!
menu
"Answer the menu for the receiver."
menu := (Menu
labels: 'Restart\Fillin\Stop'
breakLinesAtBackSlashes
selectors: #(restart fillin stop))
title: 'Fractals'.
menu disable: #stop.
^menu!
open
"Open a window to run the demo"
| aTopPane |
aTopPane := TopPane new.
aTopPane
label: 'Fractal Workspace';
model: self;
minimumSize: 300 @ 200;
windowType: Window rDocProc;
addSubpane:
(DrawPane new
name: #form:;
menu: #menu;
change: #click:;
model: self;
framingBlock: [ :box | box ]).
aTopPane menuBar addMenu: (TextPane doitMenu owner: aTopPane dispatcher)
at: 'Smalltalk'.
aTopPane whiteOnRedraw: true.
(aTopPane dispatcher
openIn: ((Screen boundingBox
insetBy: (40 @ 40)) moveBy: (0 @ 10)))
scheduleWindow!
reframe: aRectangle
"The window has been reframed."
rectangle := aRectangle.
center := rectangle center.
pen := Pen new initPen: Display;
clipRect: aRectangle.
self resolution: 10.
self from: -20@20 to: 20@-20.
self magnification: 1.
self iterations: 50.!
resolution: aNum
"Sets resolution to aNum."
resolution := aNum.!
restart
"Start drawing."
menuItem := 'restart'.
self cyclicSys.! !
(
Object subclass: #Point
instanceVariableNames:
'x y '
classVariableNames: ''
poolDictionaries: '') comment: '' !
!Point methods !
/ scale
"Answer a new Point which is the receiver Point divided
by scale. Scale can be a number or a Point. If scale
is a Point, the x-coordinates are divided and the y-
coordinates are divided."
scale class == Point
ifTrue: [^ ( x / scale x) @ ( y / scale y)]
ifFalse: [^ ( x / scale) @ ( y / scale)]! !
Object subclass: #DispatchManager
instanceVariableNames:
'dispatchers menuBar activeWindow activeDispatcher clickWindow '
classVariableNames:
'TransientWrite None '
poolDictionaries:
'SystemMenus CharacterConstants ' !
!DispatchManager methods !
menuBar
"return the current menuBar."
^ menuBar! !
MType subclass: #EventRecord
instanceVariableNames: ''
classVariableNames:
'CheckEvent TheEvent '
poolDictionaries: '' !
!EventRecord class methods !
mousePointGlobal
"Answer the current GrafPort global position of the
mouse."
| p |
p := MRecord new: 4.
MTrap GetMouse: p asParameter.
MTrap LocalToGlobal: p asParameter.
^ p asPoint! !